require('../css/json-viewer.css');
var React = require('react');
var $ = require('jquery');
var ReactDOM = require('react-dom');
var TextView = require('./textview');
var CopyBtn = require('./copy-btn');
var message = require('./message');

var JSONTree = require('./components/react-json-tree')['default'];
var dataCenter = require('./data-center');
var util = require('./util');
var MAX_LENGTH =1024 * 16;
var STR_SELECTOR = 'span[style="color: rgb(133, 153, 0);"]';
var LINK_RE = /^"(https?:)?(\/\/[^/]\S+)"$/i;

function compare(a, b) {
  return a > b ? 1 : -1;
}

var JsonViewer = React.createClass({
  getInitialState: function() {
    return { lastData: {} };
  },
  shouldComponentUpdate: function(nextProps) {
    var hide = util.getBoolean(this.props.hide);
    return hide != util.getBoolean(nextProps.hide) || !hide;
  },
  preventBlur: function(e) {
    e.target.nodeName != 'INPUT' && e.preventDefault();
  },
  edit: function() {
    var data = this.props.data;
    var str = data && data.str;
    if (str) {
      util.openEditor(str);
    }
  },
  showNameInput: function(e) {
    var self = this;
    self.state.showDownloadInput = /w-download/.test(e.target.className);
    self.state.showNameInput = true;
    self.forceUpdate(function() {
      var nameInput = ReactDOM.findDOMNode(self.refs.nameInput);
      var defaultName = !nameInput.value && self.props.defaultName;
      if (defaultName) {
        nameInput.value = defaultName;
      }
      nameInput.select();
      nameInput.focus();
    });
  },
  hideNameInput: function() {
    this.state.showNameInput = false;
    this.forceUpdate(function() {
      var nameInput = ReactDOM.findDOMNode(this.refs.nameInput);
      var defaultName = this.props.defaultName;
      if (defaultName === nameInput.value) {
        nameInput.value = '';
      }
    });
  },
  submit: function(e) {
    if (e.keyCode != 13 && e.type != 'click') {
      return;
    }
    var modal = dataCenter.valuesModal;
    if (!modal) {
      return;
    }
    var target = ReactDOM.findDOMNode(this.refs.nameInput);
    var name = target.value.trim();
    if (this.state.showDownloadInput) {
      this.download();
      return;
    }
    if (!name) {
      message.error('Value name cannot be empty.');
      return;
    }

    if (/\s/.test(name)) {
      message.error('Name cannot have spaces.');
      return;
    }
    if (modal.exists(name) &&
      !confirm('The name \'' + name + '\' already exists.\nDo you want to override it.')) {
      return;
    }

    var value = (this.state.lastData.str || '').replace(/\r\n|\r/g, '\n');
    dataCenter.values.add({name: name, value: value}, function(data, xhr) {
      if (data && data.ec === 0) {
        modal.add(name, value);
        target.value = '';
        target.blur();
      } else {
        util.showSystemError(xhr);
      }
    });
  },
  download: function() {
    var target = ReactDOM.findDOMNode(this.refs.nameInput);
    var name = target.value.trim();
    target.value = '';
    var data = this.props.data || {};
    ReactDOM.findDOMNode(this.refs.filename).value = name;
    ReactDOM.findDOMNode(this.refs.content).value = data.str || '';
    ReactDOM.findDOMNode(this.refs.downloadForm).submit();
    this.hideNameInput();
  },
  toggle: function() {
    this.setState({ viewSource: !this.state.viewSource });
  },
  componentDidMount: function() {
    var viewer = $(ReactDOM.findDOMNode(this.refs.jsonViewer));
    viewer.on('mouseenter', STR_SELECTOR, function(e) {
      if (!(e.ctrlKey || e.metaKey)) {
        return;
      }
      var elem = $(this);
      if (LINK_RE.test(elem.text())) {
        elem.addClass('w-is-link');
      }
    }).on('mouseleave', STR_SELECTOR, function() {
      $(this).removeClass('w-is-link');
    }).on('mousedown', STR_SELECTOR, function(e) {
      if (!(e.ctrlKey || e.metaKey)) {
        return;
      }
      var elem = $(this);
      if (LINK_RE.test(elem.text())) {
        window.open((RegExp.$1 || 'http:') + RegExp.$2);
      }
    });
  },
  render: function() {
    var state = this.state;
    var viewSource = state.viewSource;
    var props = this.props;
    var data = props.data;
    var noData = !data;
    if (noData) {
      data = state.lastData || {};
    } else {
      state.lastData = data;
    }
    var value = data.str || '';
    if (value && viewSource) {
      var exceed = value.length - MAX_LENGTH;
      if (exceed > 512) {
        value = value.substring(0, MAX_LENGTH) + '...\r\n\r\n(' + exceed + ' characters left, you can click on the ViewAll button in the upper right corner to view all)\r\n';
      }
    }
    return (
        <div className={'fill orient-vertical-box w-properties-wrap w-json-viewer' + ((noData || props.hide) ? ' hide' : '')}>
          <div className="w-textarea-bar">
            <CopyBtn value={data.str} />
            <a className="w-download" onDoubleClick={this.download}
              onClick={this.showNameInput} href="javascript:;" draggable="false">Download</a>
              <a className="w-add" onClick={this.showNameInput}
                href="javascript:;" draggable="false">+Value</a>
              {viewSource ? <a className="w-edit" onClick={this.edit} href="javascript:;" draggable="false">ViewAll</a> : undefined}
            <a onClick={this.toggle} className="w-properties-btn">{ viewSource ? 'ViewParsed' : 'ViewSource' }</a>
            <div onMouseDown={this.preventBlur}
              style={{display: state.showNameInput ? 'block' : 'none'}}
              className="shadow w-textarea-input"><input ref="nameInput"
              onKeyDown={this.submit}
              onBlur={this.hideNameInput}
              type="text"
              maxLength="64"
              placeholder={state.showDownloadInput ? 'Input the filename' : 'Input the key'}
            /><button type="button" onClick={this.submit} className="btn btn-primary">OK</button></div>
            <form ref="downloadForm" action="cgi-bin/download" style={{display: 'none'}}
              method="post" target="downloadTargetFrame">
              <input ref="filename" name="filename" type="hidden" />
              <input ref="content" name="content" type="hidden" />
            </form>
          </div>
          <TextView className={'fill w-json-viewer-str' + (viewSource ? '' : ' hide')} value={value} />
          <div ref="jsonViewer" className={'fill w-json-viewer-tree' + (viewSource ? ' hide' : '')}>
            <JSONTree data={data.json} sortObjectKeys={compare} />
          </div>
        </div>
    );
  }
});

module.exports = JsonViewer;
